<?php

namespace console\controllers;

use Yii;
use yii\db\Exception;
use common\models\cron\CronTask;
use common\models\cron\CronTaskLog;

/**
 * 计划任务
 *
 * @author emhome <emhome@163.com>
 * @since 1.0
 */
class CronController extends \yii\console\Controller {

    /**
     * @return mixed
     */
    public function actionIndex() {
        $tasks = CronTask::findAllActiveTasks();
        if (empty($tasks)) {
            Yii::info('暂无待执行计划任务', 'cron');
            return false;
        }
        $runStates = [
            'counts' => count($tasks)
        ];
        foreach ($tasks as $task) {
            $status = $this->handle($task);
            if (!isset($runStates[$status])) {
                $runStates[$status] = 0;
            }
            $runStates[$status] ++;
        }
        Yii::info([
            'TRS' => 'TaskRunState',
            'states' => $runStates
        ], 'cron');
        return true;
    }

    /**
     * 自动执行任务
     * @param CronTask $task
     * @return mixed
     */
    protected function handle($task) {
        if (!$task) {
            static::taskLog('计划任务不存在', $task);
            return 'NotFound';
        }
        $model = $task->getHandleModel();
        if (!$model) {
            static::taskLog([
                '计划任务无明确内容',
                $task->attributes,
                $task->getHandleModel(),
            ], $task);
            return 'NoOperation';
        }
        if (!$model instanceof \console\crons\HandleTaskInterface) {
            static::taskLog('无效的计划任务', $task);
            return 'InvalidTaskHandle';
        }
        if ($model->isRunning()) {
            static::taskLog('计划任务正在执行', $task);
            return 'Running';
        }
        if ($model->isDone()) {
            static::taskLog('计划任务已执行完成', $task);
            return 'Done';
        }
        $log = null;
        $taskStatus = $model->handle();
        if (!$taskStatus) {
            $log = new CronTaskLog();
            $log->task_id = $task->id;
            $log->operation = '计划任务执行失败';
            $log->explain = $model->getErrorMsg();
        }
        $task->last_time = time();
        //执行任务
        $transaction = Yii::$app->db->beginTransaction();
        try {
            if (!$task->save()) {
                throw new Exception($task->getErrorMsg());
            }
            if ($log) {
                if (!$log->save()) {
                    throw new Exception($log->getErrorMsg());
                }
            }
            $transaction->commit();
        } catch (Exception $e) {
            // 记录回滚（事务回滚）
            $transaction->rollBack();
            static::taskLog([
                'message' => '计划任务状态更新失败',
                'error' => $e->getMessage(),
            ], $task);
            return 'Error';
        }
        return 'Success';
    }

    /**
     * 自动执行任务
     * @param mixed $message
     * @param CronTask $model
     * @return mixed
     */
    protected static function taskLog($message, $model) {
        Yii::error([
            'IDENTIFY' => $model->name, // '计划任务',
            'TASK' => $model->title,
            'RUNTIME' => date('Y-m-d H:i:s'),
            'MESSAGE' => $message,
        ], 'cron');
    }

}
